﻿#region Librerias

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography;
using ESF.General.Entity;
using System.IO;

#endregion


namespace ESF.General
{
	public static class DigitalSignHelper
	{
		public static List<X509Certificate2> ListUserCertificates()
		{
			List<X509Certificate2> certificates;

			X509Store objStore;


			certificates = new List<X509Certificate2>();

			#region Certificados Token (instalados)

			objStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);

			objStore.Open(OpenFlags.ReadOnly);

			foreach (X509Certificate2 cert in objStore.Certificates)
			{
				if (cert.Extensions.Count > 0 && DateTime.Compare(cert.NotAfter, DateTime.Now.AddHours(-2)) >= 0)
				{
					certificates.Add(cert);
				}
			}

			objStore.Close();

			#endregion

			return certificates;
		}


		public static List<CertificateResumen> ListUserCertificatesResumen()
		{
			List<CertificateResumen> result;
			List<X509Certificate2> certs;

			
			result = new List<CertificateResumen>();


			certs = ListUserCertificates();

			foreach (X509Certificate2 cert in certs)
			{
				result.Add(new CertificateResumen(cert, false));
			}

			return result;
		}


		public static X509Certificate2 GetCertificate(string pCertificateTumbprint)
		{
			List<X509Certificate2> certs;

			
			certs = ListUserCertificates();

			if (DataHelper.IsEmpty(certs)) { return null; }

			return certs.Find(c => c.Thumbprint == pCertificateTumbprint);
		}


		public static CertificateResumen GetCertificateResumen(string pCertificateTumbprint)
		{
			X509Certificate2 cert;


			cert = GetCertificate(pCertificateTumbprint);

			if (cert == null) { return null; }

			return new CertificateResumen(cert, false);
		}


		public static string SignFile(string pOriginalFileName, string pOriginalFileDescription, string pFileNameToSign, string pCertificateTumbprint, bool pDeleteFile)
		{
			List<CertificateResumen> certRess;
			List<CertificateResumen> selected;

			X509Certificate2 objCert;

			string signedFileName;


			certRess = ListUserCertificatesResumen();

			selected = certRess.FindAll(c => c.Thumbprint == pCertificateTumbprint);

			// Hay mas de un certificado igual con firma
			if (selected.Count > 1)
			{
				if (selected.Exists(c => c.FromFile))
				{
					objCert = selected.Find(c => c.FromFile).Certificate;
				}
				else
				{
					objCert = selected.First().Certificate;
				}
			}
			else if (selected.Count == 1)
			{
				objCert = selected.First().Certificate;
			}
			else
			{
				throw new GenericInfoException("Revise su configuración de firma digital, el Certificado seleccionado no esta disponible (conecte sus token si usa alguno)");
			}

			ContentInfo objContent = new ContentInfo(File.ReadAllBytes(pFileNameToSign));

			//Creamos el objeto que representa los datos firmados
			SignedCms objSignedData = new SignedCms (objContent);

			//Creamos el "firmante"
			CmsSigner objSigner = new CmsSigner(objCert)
			{
				SignedAttributes = 
					{
						new Pkcs9SigningTime(),
						new Pkcs9DocumentName (pOriginalFileName),
						new Pkcs9DocumentDescription (pOriginalFileDescription)
					}
			};

			//Firmamos los datos
			objSignedData.ComputeSignature(objSigner, false);

			if (pDeleteFile)
			{
				FileHelper.Delete(pFileNameToSign);
			}

			signedFileName = pFileNameToSign + ".p7z";

			//Obtenemos el resultado, garantizamos que se pueda sobreescribir
			FileHelper.Delete(signedFileName);

			File.WriteAllBytes(signedFileName, objSignedData.Encode());

			return signedFileName;
		}


		public static CertificateResumen GetCertificateResumenFromSignedFile (string pFileName)
		{
			return new CertificateResumen (GetCertificateFromSignedFile (pFileName));
		}


		public static X509Certificate2 GetCertificateFromSignedFile (string pFileName)
		{
			return new X509Certificate2(X509Certificate2.CreateFromSignedFile(pFileName));
		}


		public static bool VerifySignedFile(string pFileName)
		{
			return GetCertificateFromSignedFile (pFileName).Verify();
		}
	}
}
